package com.len.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.len.config.PrestoDataSource;
import com.len.entity.Behavior;
import com.len.entity.BehaviorField;
import com.len.entity.ReportConfig;
import com.len.mapper.BehaviorFieldMapper;
import com.len.mapper.BehaviorMapper;
import com.len.mapper.ReportConfigMapper;
import com.len.service.ReportService;
import com.len.utils.SqlConstructor;
import com.len.vo.ColsVo;
import com.len.vo.ParameterInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.*;

/**
 * @author songxiangyang
 * @date 2019/03/15.
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    ReportConfigMapper reportConfigMapper;
    @Autowired
    BehaviorFieldMapper behaviorFieldMapper;
    @Autowired
    BehaviorMapper behaviorMapper;
    @Autowired
    private PrestoDataSource prestoDataSource;

    @Override
    public List<Map<String, String>> getReportMeasureByReportId(String reportId) {
        String measureIds = "";
        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
        String cube = reportConfig.getCube();
        JSONObject jsonObject = (JSONObject) JSON.parse(cube);
        JSONArray measureIdJsonArray = jsonObject.getJSONArray("measureId");
        for (int i = 0; i < measureIdJsonArray.size(); i++) {
            measureIds += "'" + measureIdJsonArray.get(i).toString() + "',";
        }
        if (StringUtils.isNotBlank(measureIds)) {
            measureIds = measureIds.substring(0, measureIds.length() - 1);
        }
        List<BehaviorField> behaviorMeasureFields = behaviorFieldMapper.selectByIds(measureIds);
        List<Map<String, String>> data = new ArrayList<>();
        Map<String, String> map = new HashMap();
        behaviorMeasureFields.forEach(df -> {
            String id = df.getId();
            String fieldLabel = df.getFieldLabel();
            map.put(id, fieldLabel);
        });
        data.add(map);
        return data;
    }

    @Override
    public List<LinkedHashMap<Object, Object>> getTableData(ParameterInfo parameterInfo) throws IOException {
        SqlConstructor sqlConstructor = null;
        Behavior behavior = null;
        // 查找报表配置
        String reportId = parameterInfo.getReportId();
        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
        String cubeJson = reportConfig.getCube();
        JSONObject jsonObject = (JSONObject) JSON.parse(cubeJson);
        // 查找该报表对应的所有维度
        JSONArray dimentionIdJsonArray = jsonObject.getJSONArray("dimentionId");
        List<BehaviorField> behaviorDimensionFields = new ArrayList<>();
        Integer chartType = parameterInfo.getChartType();
        Integer ii = 0;
        if(chartType == 1) {
            ii = 1;
        }
        for (int i = ii; i < dimentionIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(dimentionIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorDimensionFields.add(b);
        }
        // 查找该报表对应的所有量度
        JSONArray measureIdJsonArray = jsonObject.getJSONArray("measureId");
        List<BehaviorField> behaviorMeasureFields = new ArrayList<>();
        for (int i = 0; i < measureIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(measureIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorMeasureFields.add(b);
        }
        // 查询对应的行为 准备拼接sql
        if (behaviorDimensionFields.size() > 0) {
            String behaviorId = behaviorDimensionFields.get(0).getBehaviorId();
            behavior = behaviorMapper.selectByPrimaryKey(behaviorId);
        }
        // 拼接sql基本骨架 SELECT FROM picc.pc_log_data pc_log  WHERE 1 = 1  LIMIT 5000
        if (behavior != null) {
            sqlConstructor = new SqlConstructor(behavior);
        }
        // 拼接 维度(select group部分)
        if (sqlConstructor != null) {
            for (BehaviorField behaviorField : behaviorDimensionFields) {
                sqlConstructor.agg(behaviorField.getFieldName(), behaviorField.getAlias());
            }
        }
        // 拼接量度 (select部分)
        if (sqlConstructor != null) {
            for (BehaviorField behaviorField : behaviorMeasureFields) {
                sqlConstructor.measure(behaviorField.getFieldName(), behaviorField.getAlias());
            }
        }
        String queryCondition = parameterInfo.getDsl();
        Example example =new Example(BehaviorField.class);
        example.createCriteria().andEqualTo("fieldType","date").andEqualTo("behaviorId", reportConfig.getBehaviorId());
        BehaviorField behaviorField = behaviorFieldMapper.selectOneByExample(example);
        sqlConstructor.filterDateranger(parameterInfo.getDateRange(),behaviorField.getFieldName());
        sqlConstructor.filter(queryCondition);
        String sql = sqlConstructor.getSql();
        log.info("sql:" + sql);
        List<LinkedHashMap<Object, Object>> allData = prestoDataSource.getAllData(sql);
        return allData;
    }

    @Override
    public List<Map<String, Object>> getQueryBuilderByReportId(String reportId) {
        return generateQueryBuilderField(reportId);
    }

    @Override
    public List<ColsVo> getTableCols(ParameterInfo parameterInfo) {
        List<ColsVo> colsVoList = new ArrayList<>();
        // 查找报表配置
        String reportId = parameterInfo.getReportId();
        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
        String cubeJson = reportConfig.getCube();
        JSONObject jsonObject = (JSONObject) JSON.parse(cubeJson);
        // 查找该报表对应的所有维度
        JSONArray dimentionIdJsonArray = jsonObject.getJSONArray("dimentionId");
        List<BehaviorField> behaviorDimensionFields = new ArrayList<>();
        Integer chartType = parameterInfo.getChartType();
        Integer ii = 0;
        if(chartType == 1){
            ii = 1;
        }
        for (int i = ii; i < dimentionIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(dimentionIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorDimensionFields.add(b);
        }
        // 查找该报表对应的所有量度
        JSONArray measureIdJsonArray = jsonObject.getJSONArray("measureId");
        List<BehaviorField> behaviorMeasureFields = new ArrayList<>();
        for (int i = 0; i < measureIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(measureIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorMeasureFields.add(b);
        }
        // 拼接 维度(select group部分)
        for (BehaviorField behaviorField : behaviorDimensionFields) {
            ColsVo colsVo = new ColsVo();
            colsVo.setField(behaviorField.getAlias());
            colsVo.setTitle(behaviorField.getFieldLabel());
            colsVo.setSort(true);
            if (colsVoList.size() == 0){
                colsVo.setTotalRowText("合计:");
                colsVo.setTotalRow(false);
            } else {
                colsVo.setTotalRowText("");
                colsVo.setTotalRow(false);
            }
            colsVoList.add(colsVo);
        }
        // 拼接量度 (select部分)
        for (BehaviorField behaviorField : behaviorMeasureFields) {
            ColsVo colsVo = new ColsVo();
            colsVo.setField(behaviorField.getAlias());
            colsVo.setTitle(behaviorField.getFieldLabel());
            colsVo.setSort(true);
            if("int".equals(behaviorField.getFieldType())){
                colsVo.setTotalRowText("");
                colsVo.setTotalRow(true);
            } else {
                colsVo.setTotalRowText("");
                colsVo.setTotalRow(false);
            }
            colsVoList.add(colsVo);
        }
        return colsVoList;
    }

    @Override
    public String getCloudChartsData(ParameterInfo parameterInfo) {
        String sql = getChartSql(parameterInfo).get("sql").toString();
        List<LinkedHashMap<Object, Object>> allData = prestoDataSource.getAllData(sql);
        List valList = new ArrayList();
        for (Map<Object, Object> map : allData) {
            Collection values = map.values();
            List list = new ArrayList(values);
            valList.add(list.toArray());
        }
        String jsonString = JSONObject.toJSONString(valList);
        return jsonString;
    }

//    @Override
//    public Map<String, Object> getDiffTableData(ParameterInfo parameterInfo) {
//        SqlConstructor nowWhereConstructor = null;
//        SqlConstructor laHuanWhereConstructor = null;
//        SqlConstructor laTongWhereConstructor = null;
//        // 查找报表配置
//        String reportId = parameterInfo.getReportId();
//        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
//        String oldSql = reportConfig.getCube();
//        Example example =new Example(BehaviorField.class);
//        example.createCriteria().andEqualTo("fieldType","date").andEqualTo("behaviorId", reportConfig.getBehaviorId());
//        BehaviorField behaviorField = behaviorFieldMapper.selectOneByExample(example);
//        String queryCondition = parameterInfo.getDsl();
//        nowWhereConstructor = new SqlConstructor();
//        laHuanWhereConstructor = new SqlConstructor();
//        laTongWhereConstructor = new SqlConstructor();
//        String nowDateRange = parameterInfo.getDateRange();
//        String laHuanDateRange = DateUtil.getTongCompareDayStr(nowDateRange);
//        String laTongDateRange = parameterInfo.getCompareDateRange();
//        nowWhereConstructor.filterDateRange(nowDateRange,behaviorField.getFieldName());
//        laHuanWhereConstructor.filterDateRange(laHuanDateRange,behaviorField.getFieldName());
//        laTongWhereConstructor.filterDateRange(laTongDateRange,behaviorField.getFieldName());
//
//        nowWhereConstructor.filter(queryCondition);
//        laHuanWhereConstructor.filter(queryCondition);
//        laTongWhereConstructor.filter(queryCondition);
//        String wherenow = nowWhereConstructor.getWhere();
//        String wherehuan = laHuanWhereConstructor.getWhere();
//        String wheretong = laTongWhereConstructor.getWhere();
//        Map root = new HashMap();
//        root.put("wherenow", wherenow);
//        root.put("wherehuan", wherehuan);
//        root.put("wheretong", wheretong);
//        String newSql = TemplateEngineUtils.createTemplate(oldSql, root);
//        log.info("sql:{}",newSql);
//        List<LinkedHashMap<Object, Object>> allData = prestoDataSource.getAllData(newSql);
//        List<LinkedHashMap<Object, Object>> finalAllData = new ArrayList<>();
//
//        List<ColsVo> colsVos = new ArrayList<>();
//        for(LinkedHashMap<Object, Object> datamap : allData){
//            LinkedHashMap<Object, Object> data = new LinkedHashMap<>();
//            for(Map.Entry<Object, Object> entry : datamap.entrySet()){
//                ColsVo colsVo = new ColsVo();
//                String[] splitedKey = entry.getKey().toString().split("#");
//                colsVo.setField(splitedKey[0]);
//                colsVo.setTitle(splitedKey[1]);
//                colsVo.setSort(true);
//                colsVo.setWidth("15%");
//                String value = entry.getValue().toString();
//                if(splitedKey[1].contains("比")){
//                    value += "%";
//                }
//                data.put(splitedKey[0], value);
//                Integer isExist = 0;
//                for(ColsVo cols : colsVos){
//                    if(colsVo.getField().equals(cols.getField())){
//                        isExist = 1;
//                        break;
//                    }
//                }
//                if(isExist == 0){
//                    colsVos.add(colsVo);
//                }
//            }
//            finalAllData.add(data);
//        }
//        Map<String, Object> result = new HashMap<>();
//        result.put("datas", finalAllData);
//        String closJsonStr = JSON.toJSONString(colsVos);
//        result.put("cols", closJsonStr);
//        result.put("size", finalAllData.size());
//        return result;
//    }

    @Override
    public String getLineChartsData(ParameterInfo parameterInfo) {
        Map<String, Object> chartSql = getChartSql(parameterInfo);
        String sql = chartSql.get("sql").toString();
        List<String> alias = (List<String>) chartSql.get("alias");
        List<LinkedHashMap<Object, Object>> allData = prestoDataSource.getAllData(sql);

        Map<String, Object> result = new HashMap();
        Set<String> dates = new TreeSet<>();
        Map<String, List<Object>> datas = new HashMap<>();
        Set<String> legend = new TreeSet<>();
        if (parameterInfo.getChartType()==0 && alias.size() == 3) {
            for (Map<Object, Object> entity : allData) {
                String date = entity.get(alias.get(0))==null?"NULL":entity.get(alias.get(0)).toString();
                dates.add(date);
                List<Object> values = datas.get(entity.get(alias.get(1))==null?"NULL":entity.get(alias.get(1)).toString());
                legend.add(entity.get(alias.get(1))==null?"NULL":entity.get(alias.get(1)).toString());
                if (values == null) {
                    values = new ArrayList<>();
                    datas.put(entity.get(alias.get(1))==null?"NULL":entity.get(alias.get(1)).toString(), values);
                }
                values.add(entity.get(alias.get(2)) == null ? 0 : entity.get(alias.get(2)));
            }
            result.put("dates", dates);
            result.put("datas", datas);
            result.put("legend", legend);
            String jsonString = JSONObject.toJSONString(result);
            System.out.println(jsonString);
            return jsonString;
//        } else if (parameterInfo.getChartType()==1 && alias.size() == 2) {
        } else if (alias.size() == 2) {
            List dimensions = new ArrayList();
            List measure = new ArrayList();
            for (Map<Object, Object> entity : allData) {
                dimensions.add(entity.get(alias.get(0))==null?"NULL":entity.get(alias.get(0)).toString());
                measure.add(entity.get(alias.get(1))==null?0:entity.get(alias.get(1)));
            }
            datas.put("dimensions", dimensions);
            datas.put("measure", measure);
            result.put("datas", datas);
            String jsonString = JSONObject.toJSONString(result);
            return jsonString;
        }
        return null;
    }

    private List<Map<String, Object>> generateQueryBuilderField(String reportId) {
        List<Map<String, Object>> maps = new ArrayList<>();
        Behavior behavior = null;
        // 查找报表配置
        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
        String bid = reportConfig.getBehaviorId();
        BehaviorField bf = new BehaviorField();
        bf.setBehaviorId(bid);
        bf.setAggFlag(0);
        List<BehaviorField> behaviorDimensionFields = behaviorFieldMapper.select(bf);
        if (behaviorDimensionFields.size() > 0) {
            String behaviorId = behaviorDimensionFields.get(0).getBehaviorId();
            behavior = behaviorMapper.selectByPrimaryKey(behaviorId);
        }

        if (behavior != null) {

            for (BehaviorField behaviorField : behaviorDimensionFields) {
                Map<String, Object> map = new HashMap<>();
                String tableAlias = behavior.getAlias();
                map.put("id", tableAlias + "." + behaviorField.getFieldName());
                map.put("label", behaviorField.getFieldLabel());
                map.put("type", behaviorField.getFieldType());
                if(StringUtils.isNotBlank(behaviorField.getFieldDictType())) {
                    String sql = "select key as id, value as name from lookup.report_lookup where type='"+behaviorField.getFieldDictType()+"'";
                    List<LinkedHashMap<Object, Object>> allData = prestoDataSource.getAllData(sql);
                    Map<String, Object> pluginMap = new HashMap<>();
                    pluginMap.put("valueField", "id");
                    pluginMap.put("labelField", "name");
                    pluginMap.put("searchField", "name");
                    pluginMap.put("sortField", "name");
                    pluginMap.put("options", allData);
                    map.put("input", "select");
                    map.put("multiple", true);
                    map.put("plugin", "selectize");
                    map.put("plugin_config", pluginMap);
                }
                maps.add(map);
            }
//      Map joinReferParams = new HashMap();
//      joinReferParams.put("reportId", reportId);
//      dimensionParams.put("sidx", "sort_num");
//      dimensionParams.put("order", "asc");
//      List<RpTReportModelJoinReferEntity> reportModelJoinReferList = joinReferDao.queryList(joinReferParams);
//      for (RpTReportModelJoinReferEntity reportModelJoinRefer : reportModelJoinReferList) {
//        List<Map<String, Object>> referReportDimensionList = generateQueryBuilderField(reportModelJoinRefer.getSonReportDimensionEntity().getReportEntity().getId());
//        maps.addAll(referReportDimensionList);
//      }
            return maps;
        }
        return null;
    }

    private Map<String, Object> getChartSql(ParameterInfo parameterInfo){
        Map result = new HashMap();
        SqlConstructor sqlConstructor = null;
        Behavior behavior = null;
        List<String> alias = new ArrayList<>();
        // 查找报表配置
        String reportId = parameterInfo.getReportId();
        ReportConfig reportConfig = reportConfigMapper.selectByPrimaryKey(reportId);
        String cubeJson = reportConfig.getCube();
        JSONObject jsonObject = (JSONObject) JSON.parse(cubeJson);
        // 查找该报表对应的所有维度
        JSONArray dimentionIdJsonArray = jsonObject.getJSONArray("dimentionId");
        List<BehaviorField> behaviorDimensionFields = new ArrayList<>();
        Integer chartType = parameterInfo.getChartType();
        Integer ii = 0;
        if(chartType == 1){
            ii = 1;
        }
        for (int i=ii; i < dimentionIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(dimentionIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorDimensionFields.add(b);
        }
        // 查找该报表对应的所有量度
        JSONArray measureIdJsonArray = jsonObject.getJSONArray("measureId");
        List<BehaviorField> behaviorMeasureFields = new ArrayList<>();
        for (int i = 0; i < measureIdJsonArray.size(); i++) {
            BehaviorField behaviorField = new BehaviorField();
            behaviorField.setId(measureIdJsonArray.get(i).toString());
            BehaviorField b = behaviorFieldMapper.selectByPrimaryKey(behaviorField);
            behaviorMeasureFields.add(b);
        }
        // 查询对应的行为 准备拼接sql
        if (behaviorDimensionFields.size() > 0) {
            String behaviorId = behaviorDimensionFields.get(0).getBehaviorId();
            behavior = behaviorMapper.selectByPrimaryKey(behaviorId);
        }
        // 拼接sql基本骨架 SELECT FROM picc.pc_log_data pc_log  WHERE 1 = 1  LIMIT 5000
        if (behavior != null) {
            sqlConstructor = new SqlConstructor(behavior);
        }
        // 拼接 维度(select group部分)
        if (sqlConstructor != null) {
            for (BehaviorField behaviorField : behaviorDimensionFields) {
                sqlConstructor.agg(behaviorField.getFieldName(), behaviorField.getAlias());
                alias.add(behaviorField.getAlias());
            }
        }
        // 拼接量度 (select部分)
        if (sqlConstructor != null) {
            for (BehaviorField behaviorField : behaviorMeasureFields) {
                if (behaviorField.getId().equals(parameterInfo.getChartsMeasureId())) {
                    sqlConstructor.measure(behaviorField.getFieldName(), behaviorField.getAlias());
                    sqlConstructor.order(behaviorField.getAlias(), 1, "desc");
                    alias.add(behaviorField.getAlias());
                }
            }
        }
        // 拼接where
//        String queryCondition = Tools.getQueryCondition(parameterInfo.getDsl());
        String queryCondition = parameterInfo.getDsl();
        Example example =new Example(BehaviorField.class);
        example.createCriteria().andEqualTo("fieldType","date").andEqualTo("behaviorId", reportConfig.getBehaviorId());
        BehaviorField behaviorField = behaviorFieldMapper.selectOneByExample(example);
        sqlConstructor.filterDateranger(parameterInfo.getDateRange(),behaviorField.getFieldName());
        sqlConstructor.filter(queryCondition);
        sqlConstructor.limit(parameterInfo.getLimit());
        String sql = sqlConstructor.getSql();
        result.put("sql", sql);
        result.put("alias", alias);
        return result;
    }

}
